ReactNative 开发Android App | 您所在的位置:网站首页 › react android开发 › ReactNative 开发Android App |
Android开发平台
谷歌在2007年发布Android 是一个开源的基于 Linux 的移动设备操作系统 支持的设备: phone… 语言: 开发语言是java , 后来因为甲骨文准备对android java收费, 又开始向Kotlin转移 IDE: 开发工具以前是eclipse+sdk, 后来谷歌退出了独立的IDE, Android Studio 打包: 使用签名打包生成.apk文件, 可作为app, 安装在android系统. 可用的平台框架 现在开发app主要有四种可选方案 首先是原生, 性能最好, 可是针对不同平台业务代码需要重复开发, 并且每次发版都需要经过应用市场审核 所以为了解决这个问题, 衍生出Cordove+ionic+web的方案, cordova 是Apache的开源框架, 由PhoneGap演化而来, 提供的是跨平台运行在各种设备的app壳 Ionic 为Web页面提供UI界面和交互. 然而web版本性能方面有些欠缺. 所以Facebook推出ReactNative采用virtual DOM与native UI控件进行绑定, 因此很好待解决了性能问题. Flutter使用dart 替换掉JS和V8, 性能据说有有更好的提升. Android 架构> Linux内核层 主要包含硬件相关的驱动, 电源管理, 以及内核本身的文件管理, 线程调度, 权限管理, 内存管理等. > 硬件抽象层 通过抽象封装硬件“驱动”的接口来进一步降低Android系统与硬件的耦合度; > 运行库: 运行时: 核心库, Dalvik 虚拟机(使各java应用拥有独立的进程) C++库: Sqlite, webkit, media, audio, ssl, openGL, freetype > JAVA的应用框架: Activity, Windows, View, notification, package, Telephony, location, resource. > APP应用 短信, 浏览器, 拨号, 计算器, …. 从Js 层到Java层前面说明了android系统从底层到app的整体架构, 接下来说明一下react-native 实现的android app是怎么交互的. 画这个图的人把上下颠倒了一下. > Java层: 该层主要提供了Android的UI渲染器UIManager(将JavaScript映射成Android Widget) > Android Widget 控件 Fresco图片加载, okhttp 提供http请求, 对于ios, 或者windows, 这一层都是native层的类似模块. > JSEngine: 提供js运行环境 > JSBridage: 负责上下层的通信. > JavaScript层: 运行的是react native 的js代码, 包含时间分发, js组件 等 Android Studio开发工具谷歌提供了统一的夸平台的IDE Android Studio来开发安卓应用, 包含 1. 代码编辑 . 2. 布局预览和编辑 3. 性能分析 4. 模拟器 5. 编译 / 调试 6. 查看和操作 android 设备上的文件React Native开发过程中, 这个IDE使用主要是跟模拟器相关的, Environment环境配置 环境上, 需要安装react native命令行工具, python2, JDK和android studio. 添加环境变量, 给android studio安装插件和包. 其中包含sdk, 平台工具, intel硬件加速管理, 模拟器, 27版的api, 从右图可以看到27对应的是android8.1, 之所以不使用最新的28, 是因为目前还不够稳定. x86的系统, 用于模拟器启动android. 安装好react-native命令行工具, 就可以创建出工程了. 工程里包含android的工程, ios的工程, 依赖的模块, 和app.js, index.js. 进入工程目录, 就可以跑起来打包安装了. Emulator模拟器安装或调试之前需要先配一个模拟器 或者将一个android设备配置mtp权限通过usb链接电脑. ADB(Android Debug Bridge)调试器 path添加: AppData\Local\Android\Sdk\platform-tools 查看设备: adb devices 远程: adb shell 安装: adb install xxx.apk 卸载: adb uninstall xxx.apk 下载: adb pull 上传: adb push 日志: adb logcatAndroid 的一个通用命令行工具, 帮助PC与模拟器实例或连接的 Android 设备进行通信 首先添加环境变量path添加androidsdk的工具路径 然后就可以通过命令行控制了 Adb会在5037端口运行起来一个负责电脑与设备通信的服务. AndroidManifest.xml 应用初始化清单在 Android 系统启动应用组件之前, 系统通过读取应用的清单, 得知以下信息: 1. 报名, 版本名, 版本号, 默认安装位置 2. 硬件功能: 如相机, 蓝牙, GPS等. 3. 用户权限: 流量, 联系人, 相册, 读写存储等. 4. 需要链接的API库. 5. 启动状态, 比如横屏, 竖屏, 感应, 键盘等. 这里面还有很多节点和属性, 这里就不一一例举了. link链接链接的意思是在android 和 ios 工程中引入对某个native库的导入和依赖. 如果手动修改需要找到好几个文件一一添加. 使用命令则可以自动完成这个步骤. 这样做的目的是, 减少不必要库的加载, 从而缩小打包大小. react-native link xxx android/app/build.gradle android/app/src/main/java/com/AppName/MainApplication.java android/settings.gradle ios/AppName.xcodeproj/project.pbxproj Touchable可触摸组件 TouchableHighlight TouchableNativeFeedback TouchableOpacity TouchableWithoutFeedback onLayout?: (event: LayoutChangeEvent) => void;onLongPress?: (event: GestureResponderEvent) => void; onPress?: (event: GestureResponderEvent) => void;onPressIn?: (event: GestureResponderEvent) => void;onPressOut?: (event: GestureResponderEvent) => void; pressRetentionOffset?: Insets; delayLongPress?: number; delayPressIn?: number; delayPressOut?: number;除了button控件, 大部分控件无法响应触摸行为. 所以需要依赖Touchable系列控件的包裹. • 背景会在用户手指按下时变暗 • 在用户按下时形成墨水涟漪 • 会在用户手指按下时降低按钮的透明度 • 不显示任何视觉反馈 Scroll滚动 ScrollView FlatList SectionList onContentSizeChange?: (w: number, h: number) => void; onScroll?: (event: NativeSyntheticEvent) => void; onScrollBeginDrag?: (event: NativeSyntheticEvent) => void; onScrollEndDrag?: (event: NativeSyntheticEvent) => void; onMomentumScrollEnd?: (event: NativeSyntheticEvent) => void; onMomentumScrollBegin?: (event: NativeSyntheticEvent) => void;滑动操作主要是针对可滚动的控件 ScrollView是基本的 FlatList针对长列表做了内存优化, 仅针对可现实范围内的部分加载到内存 SectionList也有同样的优化, 不过SectionList有分组的功能, 每个组都有独立的header和多行内容. http 请求http 请求, 可以使用fetch接口, 或者XMLHttpRequest 左边是fetch, 右边是XMLHttpRequest, 还可以使用第三方库. fetch("https://mywebsite.com/endpoint/", { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify({ firstParam: "yourValue", secondParam: "yourOtherValue" }) }) .then(response => response.json()) .then(responseJson => { return responseJson.movies; }) .catch(error => { console.error(error); }); var request = new XMLHttpRequest(); request.onreadystatechange = e => { if (request.readyState !== 4) { return; } if (request.status === 200) { console.log("success", request.responseText); } else { console.warn("error"); } }; request.open("GET", "https://mywebsite.com/endpoint/"); request.send(); File文件访问 \android\app\src\main\AndroidManifest.xml import * as RNFS from "react-native-fs"; export let FileOpt = { writeDataStr: (dataStr: string | void, pathName: string) => { if (dataStr) { RNFS.writeFile( `${RNFS.DocumentDirectoryPath}/${pathName}`, dataStr, 'utf8' ).catch((err)=>{…}); } }, readDataStr: (pathName: string): Promise => { return RNFS.readFile( `${RNFS.DocumentDirectoryPath}/${pathName}`, 'utf8' ); } }非常奇怪的是RN官方未提供对文件读写的接口. 所以不得不使用第三方提供的库. 这是我封装的文件读写操作接口. 这里需要说明的是, 写单例不能使用class, 因为会导致打包的apk闪退. 所以这里使用的是普通object的写法. 另外, android会限制app的权限, 所以需要在前面提到的AndroidManifest.xml中申明读写权限. Database数据库但是关系型数据库, 都是第三方提供的. WatermelonDB react-native-sqlite-storage 官方提供的数据库比较简陋, 只有key-value watermelonDB react-native-sqlite-storage import { AsyncStorage } from "react-native“; setCacheStr: async (keyName: string, valueStr: string | void | null) => { if (keyName && valueStr) { AsyncStorage.setItem(keyName, valueStr) .catch((err)=>{ NativeSdk.log("[StorageOpt: setCacheStr] failed:", err); }); } }, getCacheStr: (keyName: string): Promise => { return AsyncStorage.getItem(keyName); }, Navigation导航官方提供的navigator 包含tab页导航, 以及跨页面的跳转. 首先是, 定义名字和导航页面的映射. 然后在根页面层的props中可以获取到navigator对象, 使用navigator对象就可以做跳转操作了. 去到一个页面, 然后返回到前一个页面. 也经过多次跳转, 之后回到最初的页面. const TabNavigator = createBottomTabNavigator({ Collection: { screen: PhotosPage, path: '/TabsCollection', swipeEnabled: true, navigationOptions: { tabBarLabel: '照片', tabBarIcon: ({ tintColor, focused }:any) => ( ), tabBarOptions: tabBarOptions } } }) const tabPages = createAppContainer(TabNavigator); const AppNavigator = createStackNavigator({ Home: tabPages, Photo: BigPhotoPage, Setting: SettingsPage, About: AboutPage }, { initialRouteName: 'Home', headerMode: 'none', }); let PageRouterMain = createAppContainer(AppNavigator); navigation.push("Photo", { name: 'BigPhotoPage', photoParams: photoParams, photoList: photoList }) navigation.goBack() Photos手机照片获取相片就需要区分平台了, 这里获取相册访问权限, 需要调用PermissionAndroid 获取相机访问权限, 也是类似. 获取到权限之后, 调用CameraRoll.getPhotos才不会发生异常. 在主线程外解码图片 图片解码有可能会需要超过一帧的时间。在 web 上这是页面掉帧的一大因素, 因为解码是在主线程中完成的。然而在 React Native 中, 图片解码则是在另一线程中完成的。不需要改动代码去额外处理。 if (this.getPlatform() === "android") { let granted = null; if (access === "read-storage") { granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, {'title': '手机存储', 'message': '访问您的手机存储'} ); } else if (access === "camera") { granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.CAMERA, {'title': '手机摄像头', 'message': '访问您的手机摄像头'} ); } if (granted === PermissionsAndroid.RESULTS.GRANTED) { NativeSdk.log(`requestPermision ${access} granted`); } else { NativeSdk.log(`requestPermision ${access} timeout or denied`); } } } CameraRoll.getPhotos({ first: getNum, assetType: 'Photos', after: cursor }).then((Photos)=>{ resolve(Photos); }).catch(error => { reject(error); }); 需要小心哪些坑? Promise代码调试时, 大半代码, 无法下断点.安装版console.log无输出, 需要额外写文件.启动失败, 也许只是需要删除所有打包缓存文件(每个link过的), 重新运行.几乎一半的非官方库没有同时兼容ios, android.CameraRoll获取的照片地址不是实际地址, 没有后缀, 名字还经常会变.设备的USB经常需要重复多连几次.包含某些库第三方库之后可能导致打包apk失败.日志分散在好几个窗口, 发生错误时不得不一个个检查.
|
CopyRight 2018-2019 实验室设备网 版权所有 |